/**
 * ReportGear(2011)
 */
package com.reportgear.designer.gui.component.date;

import java.awt.BorderLayout;
import java.awt.Cursor;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.swing.BorderFactory;
import javax.swing.JComboBox;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.ComboBoxUI;
import javax.swing.plaf.basic.BasicComboPopup;
import javax.swing.plaf.basic.ComboPopup;
import javax.swing.plaf.metal.MetalComboBoxUI;

import com.sun.java.swing.plaf.motif.MotifComboBoxUI;
import com.sun.java.swing.plaf.windows.WindowsComboBoxUI;

/**
 * Swing组件-日期选择器
 * 
 * @version 1.0 2011-4-26
 * @author <a herf="lexloo@gmail.com">lexloo</a>
 * @since Report 1.0
 */
public class JDatePicker extends JComboBox {
	/**
	 * UID
	 */
	private static final long serialVersionUID = -3755025346070492342L;
	public static final int STYLE_CN_DATE = 0;
	public static final int STYLE_CN_DATE1 = 1;
	public static final int STYLE_CN_DATETIME = 2;
	public static final int STYLE_CN_DATETIME1 = 3;
	private int formatStyle;
	private SimpleDateFormat dateFormat;
	private SingleObjectComboBoxModel model;
	JDateDocument dateDocument;

	public JDatePicker() throws UnsupportedOperationException {
		this(3);
	}

	public JDatePicker(int style) throws UnsupportedOperationException {
		this(style, new Date());
	}

	public JDatePicker(int style, Date value) throws UnsupportedOperationException {
		this.formatStyle = STYLE_CN_DATETIME;
		this.dateFormat = null;
		this.model = new SingleObjectComboBoxModel();
		this.dateDocument = null;
		setStyle(style);
		setEditable(true);
		setCursor(new Cursor(Cursor.DEFAULT_CURSOR));

		JTextField textField = (JTextField) getEditor().getEditorComponent();
		textField.setHorizontalAlignment(JTextField.LEFT);
		this.dateDocument = new JDateDocument(textField, this.dateFormat);
		textField.setDocument(this.dateDocument);
		setModel(this.model);
		setSelectedItem((value == null) ? new Date() : value);
	}

	public void setStyle(int style) throws UnsupportedOperationException {
		this.formatStyle = style;
		this.dateFormat = getDateFormat(style);
		this.model.setDateFormat(this.dateFormat);
		if (this.dateDocument == null) {
			return;
		}

		this.dateDocument.setDateFormat(this.dateFormat);
	}

	private static SimpleDateFormat getDateFormat(int style) throws UnsupportedOperationException {
		switch (style) {
		case STYLE_CN_DATE:
			return new SimpleDateFormat("yyyy/MM/dd");
		case STYLE_CN_DATE1:
			return new SimpleDateFormat("yyyy-MM-dd");
		case STYLE_CN_DATETIME:
			return new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		case STYLE_CN_DATETIME1:
			return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		}
		throw new UnsupportedOperationException("无效的样式参数!");
	}

	public int getStyle() {
		return this.formatStyle;
	}

	public Date getSelectedDate() throws ParseException {
		return this.dateFormat.parse(getSelectedItem().toString());
	}

	public void setSelectedDate(Date date) throws ParseException {
		setSelectedItem(this.dateFormat.format(date));
	}

	public void setSelectedItem(Object date) {
		this.model.setSelectedItem(date);

		super.setSelectedItem(date);
	}

	public void updateUI() {
		Object ui = (ComboBoxUI) UIManager.getUI(this);
		if (ui instanceof MetalComboBoxUI) {
			ui = new MetalDateComboBoxUI();
		} else if (ui instanceof MotifComboBoxUI) {
			ui = new MotifDateComboBoxUI();
		} else {
			ui = new WindowsDateComboBoxUI();
		}

		setUI((ComboBoxUI) ui);
	}

	@SuppressWarnings("serial")
	private class MotifDateComboBoxUI extends MotifComboBoxUI {
		protected ComboPopup createPopup() {
			return new JDatePicker.DatePopup(this.comboBox);
		}
	}

	private class WindowsDateComboBoxUI extends WindowsComboBoxUI {
		protected ComboPopup createPopup() {
			return new JDatePicker.DatePopup(this.comboBox);
		}
	}

	private class MetalDateComboBoxUI extends MetalComboBoxUI {
		protected ComboPopup createPopup() {
			return new JDatePicker.DatePopup(this.comboBox);
		}
	}

	@SuppressWarnings("serial")
	private class DatePopup extends BasicComboPopup implements ChangeListener {
		JCalendarPanel calendarPanel = null;

		public DatePopup(JComboBox combo) {
			super(combo);
			setLayout(new BorderLayout());
			this.calendarPanel = new JCalendarPanel();
			this.calendarPanel.addDateChangeListener(this);
			add(this.calendarPanel, BorderLayout.CENTER);
			setBorder(BorderFactory.createEmptyBorder());
		}

		protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
			if (propertyName.equals("visible")) {
				if (oldValue.equals(Boolean.FALSE) && newValue.equals(Boolean.TRUE)) {
					try {
						String str = this.comboBox.getSelectedItem().toString();
						Date date = JDatePicker.this.dateFormat.parse(str);
						this.calendarPanel.setSelectedDate(date);
					} catch (Exception ex) {
						ex.printStackTrace();
					}
				} else if (!oldValue.equals(Boolean.TRUE) || !newValue.equals(Boolean.FALSE)) {
				}
			}

			super.firePropertyChange(propertyName, oldValue, newValue);
		}

		public void stateChanged(ChangeEvent event) {
			Date date = (Date) event.getSource();
			String str = JDatePicker.this.dateFormat.format(date);
			if ((this.comboBox.isEditable()) && (this.comboBox.getEditor() != null)) {
				this.comboBox.configureEditor(this.comboBox.getEditor(), str);
			}

			this.comboBox.setSelectedItem(str);
			this.comboBox.setPopupVisible(false);
		}
	}
}